Unit Semaphor;
(**
 *	Объект Semaphore, обычный семафор, ограничивайющий доступ
 *	к критическому ресурсу, и позволяющий одновременно работать
 *	с ним (ресурсом) потокам, число которых не превосходит некоторой
 *	заданной программистом положительной константы.
 *	
 *	Проще было бы хранить в listSleepProcess не сами процессы, а только их id,
 *	так как средства диспетчера позволяют реализовать семафор.
 *)
Interface
Uses List, Process, DispProc, routine;
	type 
		PSemaphore = ^TSemaphore;
		TSemaphore = object
			private
				listSleepProcess:	TList;
				numberThread:		byte;
			public
				Constructor init(const arg: byte);
				Destructor	done;
				Procedure	P;
				Procedure	V;
		end;
Implementation
(**
 *
 *	TSemaphore
 *
 *)
	Constructor TSemaphore.init;
		begin
			numberThread:=arg;
			listSleepProcess.init(sizeof(TProcess));
		end;
	Destructor TSemaphore.done;
		begin
			listSleepProcess.done;
		end;


	Procedure TSemaphore.P;
	var
		{Текущий процесс}
		cur:TProcess;
		begin
			disable_interrupt;
			{если количество возможных потоков для выполнения равно 0,
			то задерживаем текущий процесс}
			if (numberThread = 0) then
				begin
					{получаем текущий процесс}
					get_current_dispatcher^.get_current_process(cur);
					{записываем его в список "спящих" процессов}
					listSleepProcess.push_back(cur);
					{текущий процесс задерживаем, свою работу он возобновит
					после вызова операции V семафора }
					enable_interrupt;
					get_current_dispatcher^.delayProcess(cur);
				end
			else
				begin
					dec(numberThread);
					enable_interrupt;
				end;
		end;


	Procedure TSemaphore.V;
		var
			sleeping_process:TProcess;
		begin
			{запрещаем прерывания}
			disable_interrupt;
			inc(numberThread);
			{Если в списке спящих процессов есть процессы, требуется передать
			управление первому такому процессу в списке}
			if (not listSleepProcess.empty) then
				begin
					if (listSleepProcess.front(sleeping_process)) then
						begin
							{удаляем его из списка спящих процессов}
							listSleepProcess.pop_front;
							{снова уменьшаем количество потоков, допущенных
							в критический участок кода}
							dec(numberThread);
							{возобновляем его работу сейчас}
							get_current_dispatcher^.resumeProcessNow(sleeping_process);
							{разрешаем прерывания}
							enable_interrupt;
							get_current_dispatcher^.activate_next_process;
						end;
				end
			else
				{разрешаем прерывания}
				enable_interrupt;
		end;
begin
end.